﻿using System;
using System.Timers;
using System.Windows;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Input;
using System.Collections;
using System.Windows.Forms;
using System.Media;
using System.IO;

namespace AutoClicker
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);

        
        System.Timers.Timer timer;
        Properties.Settings settings;
        Dictionary<string, string> keyDictionary;
        Dictionary<string, Key> hotKeyDic;
        string[] scriptString = null;
        HotKey hKey;
        SoundPlayer soundOn;
        SoundPlayer soundOff;

        public MainWindow()
        {
            InitializeComponent();
            timer = new System.Timers.Timer();
            timer.Elapsed += timer_Elapsed;
            keyDictionary = GetKeyDictionary();
            hotKeyDic = GetHotKeyDictionary();
            KeyDropBox.ItemsSource = keyDictionary.Keys;
            HotKeyDropBox.ItemsSource = hotKeyDic.Keys;
            HotKeyPrefixBox.ItemsSource = new string[] {"","Ctrl", "Shift","Alt","Win"};
            LoadProg();
        }

        private void LoadProg()
        {
            settings = Properties.Settings.Default;
            timer.Interval = settings.interval;
            if (timer.Interval <= 5000)
                TimeSlider.Value = timer.Interval;
            KeyDropBox.SelectedIndex = settings.keyIndex;
            HotKeyDropBox.SelectedIndex = settings.hotKeyIndex;
            HotKeyPrefixBox.SelectedIndex = settings.hotKeyPrefInd;
            KeyTextBox.Text = settings.keyText;
            HotKeyTextBox.Text = settings.hotKeyText;
            string windir = Environment.GetEnvironmentVariable("windir");
            if (File.Exists(windir + @"\Media\Speech On.wav"))
                soundOn = new SoundPlayer(windir + @"\Media\Speech On.wav");
            if (File.Exists(windir + @"\Media\Speech Off.wav"))
                soundOff = new SoundPlayer(windir + @"\Media\Speech Off.wav");
            ParseKeyCode();
            CreateHotKey();
        }

        #region LoadDictionary
        private Dictionary<string, string> GetKeyDictionary()
        {
            Dictionary<string, string> keyDic = new Dictionary<string, string>();
            keyDic.Add("", "");
                keyDic.Add("Shift", "{Shift}");
                keyDic.Add("Ctrl", "{Ctrl}");
                keyDic.Add("ALT", "{Alt}");
                keyDic.Add("Левая кнопка мыши", "{LCLICK}");
                keyDic.Add("Правая кнопка мыши", "{RCLICK}");
                keyDic.Add("Средняя кнопка мыши", "{MCLICK}");
            keyDic.Add("СТРЕЛКА ВЛЕВО (←)", "{LEFT}");
            keyDic.Add("СТРЕЛКА ВПРАВО (→)", "{RIGHT}");
            keyDic.Add("СТРЕЛКА ВВЕРХ (↑)", "{UP}");
            keyDic.Add("СТРЕЛКА ВНИЗ (↓)", "{DOWN}");
            keyDic.Add("ENTER (ВВОД)", "{ENTER}");
            keyDic.Add("BACKSPACE", "{BACKSPACE}");
            keyDic.Add("CAPS LOCK", "{CAPSLOCK}");
            keyDic.Add("DELETE", "{DELETE}");
            keyDic.Add("END", "{END}");
            keyDic.Add("Esc", "{ESC}");
            keyDic.Add("HOME", "{HOME}");
            keyDic.Add("INSERT", "{INSERT}");
            keyDic.Add("NUM LOCK", "{NUMLOCK}");
            keyDic.Add("PAGE DOWN", "{PGDN}");
            keyDic.Add("PAGE UP", "{PGUP}");
            keyDic.Add("PRINT SCREEN", "{PRTSC}");
            keyDic.Add("SCROLL LOCK", "{SCROLLLOCK}");
            keyDic.Add("TAB (Табулятор)", "{TAB}");
            keyDic.Add("F1", "{F1}");
            keyDic.Add("F2", "{F2}");
            keyDic.Add("F3", "{F3}");
            keyDic.Add("F4", "{F4}");
            keyDic.Add("F5", "{F5}");
            keyDic.Add("F6", "{F6}");
            keyDic.Add("F7", "{F7}");
            keyDic.Add("F8", "{F8}");
            keyDic.Add("F9", "{F9}");
            keyDic.Add("F10", "{F10}");
            keyDic.Add("F11", "{F11}");
            keyDic.Add("F12", "{F12}");
            keyDic.Add("NUM +", "{ADD}");
            keyDic.Add("NUM -", "{SUBTRACT}");
            keyDic.Add("NUM *", "{MULTIPLY}");
            keyDic.Add("NUM /", "{DIVIDE}");
            keyDic.Add("A", "A");
            keyDic.Add("B", "B");
            keyDic.Add("C", "C");
            keyDic.Add("D", "D");
            keyDic.Add("E", "E");
            keyDic.Add("F", "F");
            keyDic.Add("G", "G");
            keyDic.Add("H", "H");
            keyDic.Add("I", "I");
            keyDic.Add("J", "J");
            keyDic.Add("K", "K");
            keyDic.Add("L", "L");
            keyDic.Add("M", "M");
            keyDic.Add("N", "N");
            keyDic.Add("O", "O");
            keyDic.Add("P", "P");
            keyDic.Add("Q", "Q");
            keyDic.Add("R", "R");
            keyDic.Add("S", "S");
            keyDic.Add("T", "T");
            keyDic.Add("U", "U");
            keyDic.Add("V", "V");
            keyDic.Add("W", "W");
            keyDic.Add("X", "X");
            keyDic.Add("Y", "Y");
            keyDic.Add("Z", "Z");
            keyDic.Add("1", "1");
            keyDic.Add("2", "2");
            keyDic.Add("3", "3");
            keyDic.Add("4", "4");
            keyDic.Add("5", "5");
            keyDic.Add("6", "6");
            keyDic.Add("7", "7");
            keyDic.Add("8", "8");
            keyDic.Add("9", "9");
            keyDic.Add("0", "0");
            keyDic.Add("-", "-");
            keyDic.Add("=", "=");
            keyDic.Add("[", "[");
            keyDic.Add("]", "]");
            keyDic.Add("\\", "\\");
            keyDic.Add(";", ";");
            keyDic.Add("\"", "\"");
            keyDic.Add(",", ",");
            keyDic.Add(".", ".");
            return keyDic;
        }

        private Dictionary<string, Key> GetHotKeyDictionary()
        {
            Dictionary<string, Key> hkDic = new Dictionary<string, Key>();
            hkDic.Add("", Key.Clear);
            hkDic.Add("СТРЕЛКА ВЛЕВО (←)", Key.Left);
            hkDic.Add("СТРЕЛКА ВПРАВО (→)", Key.Right);
            hkDic.Add("СТРЕЛКА ВВЕРХ (↑)", Key.Up);
            hkDic.Add("СТРЕЛКА ВНИЗ (↓)", Key.Down);
            hkDic.Add("ENTER (ВВОД)", Key.Enter);
            hkDic.Add("BACKSPACE", Key.Back);
            hkDic.Add("CAPS LOCK", Key.CapsLock);
            hkDic.Add("DELETE", Key.Delete);
            hkDic.Add("END", Key.End);
            hkDic.Add("Esc", Key.Escape);
            hkDic.Add("HOME", Key.Home);
            hkDic.Add("INSERT", Key.Insert);
            hkDic.Add("NUM LOCK", Key.NumLock);
            hkDic.Add("PAGE DOWN", Key.PageDown);
            hkDic.Add("PAGE UP", Key.PageUp);
            hkDic.Add("PRINT SCREEN", Key.PrintScreen);
            hkDic.Add("SCROLL LOCK", Key.Scroll);
            hkDic.Add("TAB (Табулятор)", Key.Tab);
            hkDic.Add("F1", Key.F1);
            hkDic.Add("F2", Key.F2);
            hkDic.Add("F3", Key.F3);
            hkDic.Add("F4", Key.F4);
            hkDic.Add("F5", Key.F5);
            hkDic.Add("F6", Key.F6);
            hkDic.Add("F7", Key.F7);
            hkDic.Add("F8", Key.F8);
            hkDic.Add("F9", Key.F9);
            hkDic.Add("F10", Key.F10);
            hkDic.Add("F11", Key.F11);
            hkDic.Add("F12", Key.F12);
            hkDic.Add("NUM 0", Key.NumPad0);
            hkDic.Add("NUM 1", Key.NumPad1);
            hkDic.Add("NUM 2", Key.NumPad2);
            hkDic.Add("NUM 3", Key.NumPad3);
            hkDic.Add("NUM 4", Key.NumPad4);
            hkDic.Add("NUM 5", Key.NumPad5);
            hkDic.Add("NUM 6", Key.NumPad6);
            hkDic.Add("NUM 7", Key.NumPad7);
            hkDic.Add("NUM 8", Key.NumPad8);
            hkDic.Add("NUM 9", Key.NumPad9);
            hkDic.Add("NUM /", Key.Divide);
            hkDic.Add("NUM +", Key.Add);
            hkDic.Add("NUM -", Key.Subtract);
            hkDic.Add("NUM *", Key.Multiply);
            hkDic.Add("A", Key.A);
            hkDic.Add("B", Key.B);
            hkDic.Add("C", Key.C);
            hkDic.Add("D", Key.D);
            hkDic.Add("E", Key.E);
            hkDic.Add("F", Key.F);
            hkDic.Add("G", Key.G);
            hkDic.Add("H", Key.H);
            hkDic.Add("I", Key.I);
            hkDic.Add("J", Key.J);
            hkDic.Add("K", Key.K);
            hkDic.Add("L", Key.L);
            hkDic.Add("M", Key.M);
            hkDic.Add("N", Key.N);
            hkDic.Add("O", Key.O);
            hkDic.Add("P", Key.P);
            hkDic.Add("Q", Key.Q);
            hkDic.Add("R", Key.R);
            hkDic.Add("S", Key.S);
            hkDic.Add("T", Key.T);
            hkDic.Add("U", Key.U);
            hkDic.Add("V", Key.V);
            hkDic.Add("W", Key.W);
            hkDic.Add("X", Key.X);
            hkDic.Add("Y", Key.Y);
            hkDic.Add("Z", Key.Z);
            hkDic.Add("~", Key.OemTilde);
            hkDic.Add("1", Key.D1);
            hkDic.Add("2", Key.D2);
            hkDic.Add("3", Key.D3);
            hkDic.Add("4", Key.D4);
            hkDic.Add("5", Key.D5);
            hkDic.Add("6", Key.D6);
            hkDic.Add("7", Key.D7);
            hkDic.Add("8", Key.D8);
            hkDic.Add("9", Key.D9);
            hkDic.Add("0", Key.D0);
            return hkDic;
        }
        #endregion

        #region Заполнение текст боксов

        private void KeyTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            ApplyButton.IsEnabled = true;
        }

        private void TimeTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            ApplyButton.IsEnabled = true;
        }  

        private void TimeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            SetTimeText(e.NewValue);
        }

        private void SetTimeText(double value)
        {
            if (TimeTextBox != null)
            {
                string text = "";
                if (value >= 1000)
                    text = Math.Round(value / 1000, 5) + " сек";
                if (value >= 60000)
                    text = Math.Round(value / 60000, 5) + " мин";
                if (value >= 3600000)
                    text = Math.Round(value / 3600000, 5) + " ч";
                if (text == "")
                    text = Math.Round(value, 5) + " мс";
                TimeTextBox.Text = text;
                ApplyButton.IsEnabled = true;
            }
        }

        private void HotKeyDropBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            SetHotKeyToTextBox();
        }

        private void HotKeyPrefixBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            SetHotKeyToTextBox();
        }

        private void SetHotKeyToTextBox()
        {
            if (HotKeyPrefixBox.SelectedValue != null)
                if (HotKeyPrefixBox.SelectedValue.ToString() != "")
                    HotKeyTextBox.Text = HotKeyPrefixBox.SelectedValue + " + " + HotKeyDropBox.SelectedValue;
                else
                    if (HotKeyDropBox.SelectedValue != null)
                        HotKeyTextBox.Text = HotKeyDropBox.SelectedValue.ToString();
            ApplyButton.IsEnabled = true;
        }

        private void KeyDropBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            string key = e.AddedItems[0].ToString();
            if (key == "")
            {
                KeyTextBox.Text = "";
                return;
            }
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                if (KeyTextBox.Text == "")
                    KeyTextBox.Text = keyDictionary[key];
                else
                    KeyTextBox.Text += "+" + keyDictionary[key];
            }
            else
                KeyTextBox.Text = keyDictionary[key];
            ApplyButton.IsEnabled = true;
        }

        #endregion

        private void DoClick(string key)
        {
            uint MOUSEEVENTF_LEFTDOWN = 0x02;
            uint MOUSEEVENTF_LEFTUP = 0x04;
            uint MOUSEEVENTF_RIGHTDOWN = 0x08;
            uint MOUSEEVENTF_RIGHTUP = 0x10;
            uint MOUSEEVENTF_MIDDLEDOWN = 0x20;
            uint MOUSEEVENTF_MIDDLEUP = 0x40;
            uint X = Convert.ToUInt32(Control.MousePosition.X);
            uint Y = Convert.ToUInt32(Control.MousePosition.Y);
            switch (key)
            {
                case "{LCLICK}":
                    mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
                    break;
                case "{RCLICK}":
                    mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, X, Y, 0, 0);
                    break;
                case "{MCLICK}":
                    mouse_event(MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP, X, Y, 0, 0);
                    break;
            }
        }

        #region Подсказки
        private void TimeHelpButton_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.MessageBox.Show(@"Если поставить значение 0, то команда выполниться 1 раз и больше не будет повторяться.
Интервал можно указать вручную в формате:
    [число] [ед. измерения]
Присутствуют ед. измерения: 
    милисекунды (мс), секунды (сек), минут (мин) и часы(ч).
Примеры: 
    12 мс; 15.5 сек; 1 час; 15 секунд.
В текст боксе числа автоматически округляются до 5-го знака после запятой.", "Подсказка", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void KeyHelpButton_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.MessageBox.Show(@"Клавиши можно выбрать из списка.
Если при этом зажать кнопку ctrl то они будут добавляться в конец и получится комбинация.
Так же комбинацию можно конструировать самостоятельно.", "Подсказка", MessageBoxButton.OK, MessageBoxImage.Information);
        }
        #endregion

        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            TimetStartStop();
        }

        private void StopButton_Click(object sender, RoutedEventArgs e)
        {
            TimetStartStop();
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            DoAutoClick();
        }

        private void CleanSettingsButton_Click(object sender, RoutedEventArgs e)
        {
            settings.Reset();
            LoadProg();
            ApplyButton.IsEnabled = false;
        }

        private void ApplySettings()
        {
            CreateHotKey();
            ParseKeyCode();
            ParseTimeBox();
            SaveSettings();
            ApplyButton.IsEnabled = false;
        }

        private void SaveSettings()
        {
            settings.interval = timer.Interval;
            settings.keyText = KeyTextBox.Text;
            settings.keyIndex = KeyDropBox.SelectedIndex;
            settings.hotKeyText = HotKeyTextBox.Text;
            settings.hotKeyPrefInd = HotKeyPrefixBox.SelectedIndex;
            settings.hotKeyIndex = HotKeyDropBox.SelectedIndex;
            settings.Save();
        }

        private void ParseTimeBox()
        {
            string text = TimeTextBox.Text;
            text = text.Replace(".", ",");
            string[] split = text.Split(' ');
            double value = 1000;
            if (split.Length == 1)
                value = TryParseTime(text);
            else
                if (split.Length == 2)
                {
                    value = TryParseTime(split[0]);
                    switch (split[1])
                    {
                        case "сек":
                            value *= 1000;
                            break;
                        case "мин":
                            value *= 60000;
                            break;
                        case "ч":
                            value *= 3600000;
                            break;
                        case "сек,":
                            goto case "сек";
                        case "мин,":
                            goto case "мин";
                        case "ч,":
                            goto case "ч";
                        case "секунд":
                            goto case "сек";
                        case "минут":
                            goto case "мин";
                        case "часов":
                            goto case "ч";
                        case "часа":
                            goto case "ч";
                        case "час":
                            goto case "ч";
                        case "с":
                            goto case "сек";
                        case "м":
                            goto case "мин";
                    }
                }
            SetTimeText(value);
            if (value == 0)
                timer.Interval = double.MaxValue;
            else
                timer.Interval = value;
        }

        private double TryParseTime(string text)
        {
            double value = 1000;
            try
            {
                double.TryParse(text, out value);
                SetTimeText(value);
                return value;
            }
            catch (FormatException e)
            {
                System.Windows.MessageBox.Show("Неверный формат интервала");
                timer.Stop();
            }
            return value;
        }

        private void TimetStartStop()
        {
            if (ApplyButton.IsEnabled)
                ApplySettings();
            if (timer.Interval == double.MaxValue)
            {
                DoAutoClick();
                return;
            }
            if (timer.Enabled)
            {
                timer.Stop();
                if (soundOff!=null)
                soundOff.Play();
            }
            else
            {
                timer.Start();
                if (soundOn != null)
                soundOn.Play();
            }
            StartButton.IsEnabled = !timer.Enabled;
            StopButton.IsEnabled = timer.Enabled;
        }

        private void HotKeyEvent(HotKey hotKey)
        {
            TimetStartStop();
        }

        private void CreateHotKey()
        {
            string key = "";
            string prefix = "";
            if (HotKeyDropBox.SelectedValue != null)
                key = HotKeyDropBox.SelectedValue.ToString();
            if (HotKeyPrefixBox.SelectedValue != null)
                prefix = HotKeyPrefixBox.SelectedValue.ToString();
            Key hotKey;
            KeyModifier keyMod = KeyModifier.None;
            if (key != "")
            {
                hotKey = hotKeyDic[key];
                if (prefix != "")
                {
                    if (prefix == "Ctrl")
                        keyMod = KeyModifier.Ctrl;
                    if (prefix == "Shift")
                        keyMod = KeyModifier.Shift;
                    if (prefix == "Alt")
                        keyMod = KeyModifier.Alt;
                    if (prefix == "Win")
                        keyMod = KeyModifier.Win;
                }
                if (hKey == null)
                    hKey = new HotKey(hotKey, keyMod, HotKeyEvent);
                else
                {
                    hKey = null;
                    hKey = new HotKey(hotKey, keyMod, HotKeyEvent);
                }
            }
        }

        private void ParseKeyCode()
        {
            string text = KeyTextBox.Text;
            text = text.Replace("+", "№");
            text = text.Replace("{Shift}","+");
            text = text.Replace("{Ctrl}","^");
            text = text.Replace("{Alt}", "%");
            scriptString = text.Split('№');
        }

        private void ApplyButton_Click(object sender, RoutedEventArgs e)
        {
            ApplySettings();
        }

        private void DoAutoClick()
        {
            if (scriptString != null)
                foreach (string s in scriptString)
                {
                    if (isMouseKey(s))
                        DoClick(s);
                    else
                        SendKeys.SendWait(s);
                }
        }

        private bool isMouseKey(string key)
        {
            string[] mKeys = { "{LCLICK}", "{RCLICK}", "{MCLICK}", };
            foreach (string s in mKeys)
                if (s == key)
                    return true;
            return false;
        }

           
    }
}
